package com.itheima.task.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import javax.sql.DataSource;

/**
 * 认证服务配置类
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    /**
     * todo 客户端的配置信息 -----> 有哪些客户端可以接入认证 ;
     * authorization_code : 授权码模式 ;
     * password : 密码模式
     */
/*    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("nc_client_app") //介入客户端ID
                .secret("$2a$10$VFFZb.weUMXvAxhlNNzFzesqzzzvccH3u9vm4tTYGLyksl99gnJN.") //客户端的密码
                .scopes("all") //作用范围
                .redirectUris("http://localhost") //重定向地址;
                .authorizedGrantTypes("authorization_code", "password") //OAuth2模式 ;

                .and()

                .withClient("nc_client_pc")
                .secret("$2a$10$VFFZb.weUMXvAxhlNNzFzesqzzzvccH3u9vm4tTYGLyksl99gnJN.")
                .scopes("all")
                .redirectUris("http://localhost") //重定向地址;
                .authorizedGrantTypes("authorization_code", "password");
    }
*/

    // todo 客户端的配置信息 结合数据库动态查询
    @Autowired
    private DataSource dataSource;

    @Bean
    public JdbcClientDetailsService jdbcClientDetailsService(){
        return new JdbcClientDetailsService(dataSource);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(jdbcClientDetailsService());
        super.configure(clients);
    }


    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private ClientDetailsService clientDetailsService;
    @Autowired
    private TokenStore tokenStore;
    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;

    /**
     * todo 令牌访问端点配置
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager)
                .tokenServices(tokenServices())
                .allowedTokenEndpointRequestMethods(HttpMethod.POST);
    }

    /**
     * todo 令牌端点安全约束
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.tokenKeyAccess("permitAll")
                //tokenKey当使用JwtToken且使用非对称加密时，资源服务用于获取公钥而开放的，这里指这个 endpoint完全公开
                .checkTokenAccess("permitAll")
                //checkToken这个endpoint完全公开
                .allowFormAuthenticationForClients();
        //允许表单认证(密码/授权码模式认证)
    }

    /**
     * todo 控制令牌的配置信息
     */
    @Bean
    public AuthorizationServerTokenServices tokenServices() {
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setAuthenticationManager(authenticationManager);

        tokenServices.setAccessTokenValiditySeconds(7200);//access_token的有效期 ----> 可以不设置, 默认值12小时
        tokenServices.setRefreshTokenValiditySeconds(259200);//refresh_token的有效期  ----> 可以不设置,默认值30天

        tokenServices.setClientDetailsService(clientDetailsService);
        tokenServices.setTokenStore(tokenStore);

        //todo 对原始的令牌进行增强 是用jwt令牌
        //jwtAccessTokenConverter tokenConfig配置类里定义的jwt令牌
        tokenServices.setTokenEnhancer(jwtAccessTokenConverter);

        return tokenServices;
    }

}
